import time
from aiortc_custom.logger_config import log_info, log_debug, log_warning, log_error, log_success, log_failure, log_progress, log_connection, log_media, log_stats
import sys
import asyncio
import cv2
from av import VideoFrame
from FFmpegVideoPlayer import FFmpegVideoPlayer

class VideoReceiver:
    def __init__(self, preview_manager=None):
        self.frame_count = 0
        self.last_stats_time = time.time()
        self.stats_interval = 1.0
        self.pc = None
        # 后处理时延统计（解码帧到完成显示）
        self.post_process_delays = []  # ms
        self.preview_manager = preview_manager

        # 新的FFmpeg视频播放器
        self.video_player = None
        self.player_start_time = None
        
        
    def set_peer_connection(self, pc):
        self.pc = pc

    async def handle_track(self, track):
        """处理接收的远程视频轨道，使用FFmpeg播放器进行音视频同步"""
        log_success("开始处理接收的远程视频轨道")
        log_debug("轨道信息 - kind={track_kind}, id={track_id}, readyState={track_readyState}", track_kind=track.kind, track_id=track.id, track_readyState=track.readyState)

        # 初始化FFmpeg视频播放器
        try:
            self.video_player = FFmpegVideoPlayer(window_title="WebRTC远程视频")
            success = self.video_player.start(width=640, height=480, fps=30)
            if not success:
                log_failure("FFmpeg视频播放器启动失败，回退到传统方案")
                await self._fallback_to_legacy(track)
                return

            self.player_start_time = time.time()
            log_success("FFmpeg视频播放器启动成功")

        except Exception as e:
            log_failure(f"初始化视频播放器失败: {e}")
            await self._fallback_to_legacy(track)
            return

        log_success("开始接收远程视频帧...")

        consecutive_errors = 0
        max_consecutive_errors = 10

        while True:
            try:
                # 检查轨道状态
                if track.readyState == "ended":
                    log_info("远程视频轨道已结束")
                    break

                frame = await track.recv()

                if frame and isinstance(frame, VideoFrame):
                    self.frame_count += 1
                    consecutive_errors = 0  # 重置错误计数

                    # 移除有问题的同步时间戳计算，让FFmpeg自动处理
                    # timestamp = self.player_start_time + (frame.pts * frame.time_base) if frame.pts else time.time() - self.player_start_time
                    timestamp = None  # 不使用自定义时间戳，让FFmpeg自动处理

                    # 后处理开始（格式转换）
                    pp_start = time.perf_counter()
                    display_frame = frame.to_ndarray(format="bgr24")

                    # 发送到FFmpeg播放器
                    self.video_player.write_frame(display_frame, timestamp)

                    pp_end = time.perf_counter()
                    self.post_process_delays.append((pp_end - pp_start) * 1000.0)

                    # 每秒打印一次后处理平均时延
                    now = time.time()
                    if now - self.last_stats_time >= self.stats_interval:
                        avg_pp = (sum(self.post_process_delays) / len(self.post_process_delays)) if self.post_process_delays else 0.0
                        stats = self.video_player.get_stats()
                        log_stats("视频接收统计: 后处理时延={avg_pp:.2f}ms, 帧数={frame_count}, 队列={queue_size}",
                                avg_pp=avg_pp, frame_count=self.frame_count, queue_size=stats.get('queue_size', 0))
                        self.post_process_delays.clear()
                        self.last_stats_time = now

                    # 每100帧打印一次接收统计
                    if self.frame_count % 100 == 0:
                        stats = self.video_player.get_stats()
                        log_success("已接收 {frame_count} 帧远程视频 (队列: {queue_size})",
                                  frame_count=self.frame_count, queue_size=stats.get('queue_size', 0))
                else:
                    log_info("收到空帧或无效帧")
                    consecutive_errors += 1

            except Exception as e:
                consecutive_errors += 1
                log_failure("处理接收帧错误: {error_msg}", error_msg=str(e))

                if consecutive_errors >= max_consecutive_errors:
                    log_info("连续错误次数过多 ({consecutive_errors})，停止接收", consecutive_errors=consecutive_errors)
                    break

                if "Connection" in str(e) or "closed" in str(e).lower():
                    log_info("连接已关闭，停止接收")
                    break

                # 短暂等待后继续
                await asyncio.sleep(0.1)

        # 清理资源
        if self.video_player:
            log_success("停止视频播放器...")
            self.video_player.stop()
            self.video_player = None

    async def _fallback_to_legacy(self, track):
        """回退到传统播放方案"""
        log_info("使用传统视频播放方案")

        # Windows下创建预览窗口
        if sys.platform != "linux":
            try:
                cv2.namedWindow("remote", cv2.WINDOW_NORMAL)
                cv2.resizeWindow("remote", 640, 480)
                # 将窗口移到屏幕右侧，避免与本地预览窗口重叠
                cv2.moveWindow("remote", 700, 50)
                log_success("已创建远程视频预览窗口 (640x480)")
                log_success("远程预览窗口位置: (700, 50)")
                log_success("按ESC键可退出预览")
            except Exception as e:
                log_failure("创建预览窗口失败: {e}", e=e)
        else:
            log_success("Linux系统将使用VideoPreviewManager")

        # 使用传统方案播放
        while True:
            try:
                if track.readyState == "ended":
                    break

                frame = await track.recv()
                if frame and isinstance(frame, VideoFrame):
                    display_frame = frame.to_ndarray(format="bgr24")
                    if sys.platform != "linux":
                        cv2.imshow("remote", display_frame)
                        key = cv2.waitKey(1) & 0xFF
                        if key == 27:  # ESC键
                            break
                    else:
                        if self.preview_manager:
                            self.preview_manager.update_frame(display_frame, "remote")
                else:
                    await asyncio.sleep(0.01)
            except Exception:
                await asyncio.sleep(0.1)
                break
